package com.erpoa.service.impl;

import com.alibaba.fastjson.JSON;
import com.erpoa.annotation.DataBase;
import com.erpoa.constants.DataSourceNames;
import com.erpoa.entity.PackMessage;
import com.erpoa.entity.RecMatEntity;
import com.erpoa.mapper.MaterialtransferMapper;
import com.erpoa.service.MaterialtransferService;
import com.erpoa.utils.PDAException;
import com.erpoa.utils.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

/**
 * @author chenjimin
 * @Title: MaterialtransferServiceImpl
 * @ProjectName oaerp
 * @Description: TODO
 * @date 2020/9/1015:41
 */
@Service
public class MaterialtransferServiceImpl implements MaterialtransferService {
    private static final Logger logger = LoggerFactory.getLogger(MaterialtransferServiceImpl.class);

    @Autowired
    private MaterialtransferMapper materialtransferMapper;

    @Override
    @DataBase(DataSourceNames.DSX5)
    @Transactional()
    public List<RecMatEntity> functionGetOrderPlan(PackMessage packMessage, int type) {
        List<RecMatEntity> list = new ArrayList<>();
        // TODO ????0、判断条码是否存在


        // type==1是生产中的流转 type==2是已完成的流转
        if (type == 1) {
            list = materialtransferMapper.selectRecMatEntityWithType(packMessage.getWareHouse(),
                    packMessage.getUser().getsCode(), packMessage.getMachine());
        } else {
            list = materialtransferMapper.selectRecMatEntityWithOthers(packMessage.getWareHouse(),
                    packMessage.getUser().getsCode(), packMessage.getMachine());
        }

        if (list.isEmpty()) {
            throw new PDAException("该机台没有可流转的数据");
        }
        return list;
    }

    @Override
    @DataBase(DataSourceNames.DSX5)
    @Transactional(isolation = Isolation.SERIALIZABLE)
    public synchronized void functionSubRecMat(PackMessage packMessage) {
        RecMatEntity recMatEntity = JSON.parseObject(packMessage.getMessage(), RecMatEntity.class);
        RecMatEntity ent = new RecMatEntity();
        String detailID = "";
        String InProcss = "";
        double countNeedUpdate = 0;
        double YLQty = 0;
        if (StringUtil.isEmpty(recMatEntity.getfPlanID()) || StringUtil.isEmpty(recMatEntity.getfBarCode())) {
            throw new PDAException("排程ID或者条码号不能为空");
        }
        //1  流转量不能小于0
        if (recMatEntity.getfWeight() <= 0) {
            throw new PDAException("流转量必须大于0");
        }
        // 0、判断料号是不相符
        int count = this.materialtransferMapper.countrecMatFlag(recMatEntity.getfPlanID(), recMatEntity.getfBarCode());
        if (count <= 0) {
            throw new PDAException("该批次未用于所选转出排程");
        }
        // 0、判断是否为最早批次，可调拨量是否满足调拨申请量
        float fRqsqty = 1;    //申请量
        HashMap tempMapEarliest = this.materialtransferMapper.selectrecMatWithEarliest(recMatEntity.getfPlanID(), recMatEntity.getfBarCode());
        if (StringUtil.isEmpty(tempMapEarliest)) {
            throw new PDAException("根据排程ID和批次号未查询到最早批次数据，请确认！");
        }
        detailID = String.valueOf(tempMapEarliest.get("FID"));
        ent.setfRecID(String.valueOf(tempMapEarliest.get("FPARENTID")));
        ent.setfMatCode(String.valueOf(tempMapEarliest.get("FMATCODE")));
        fRqsqty = tempMapEarliest.get("FRQSQTY") == null ? 0 : Float.valueOf(tempMapEarliest.get("FRQSQTY").toString());
        if (fRqsqty == 0) {
            throw new PDAException("该笔领料的可申请量为0,不能流转！");
        }
        double sfaNum = 0; //应发数量
        // 1、查询出拨入物料所对应的作业类型
        HashMap tempMapsfa = this.materialtransferMapper.selectSfaByNoCode(recMatEntity.getfInOrderNo(), ent.getfMatCode());//recMatEntity.fInOrderNo, ent.fMatCode
        if (StringUtil.isEmpty(tempMapsfa)) {
            throw new PDAException("转入工单无此下阶料，不能流转");
        }
        InProcss = String.valueOf(tempMapsfa.get("SFA08"));
        sfaNum = tempMapsfa.get("SFA05") == null ? 0 : Double.valueOf(tempMapsfa.get("SFA05").toString());
        // 作业类型不会为空，如果为空的话，只能说明是转入的单，没有这个料
        if (InProcss.length() < 0 || InProcss.isEmpty()) {
            throw new PDAException("转入工单无此下阶料，不能流转");
        }
        //liujiajie 2019-02-12 应发为0不能流转
        if (sfaNum <= 0) {
            throw new PDAException("转入工单应发量小于或等于0，不能流转");
        }
        // 2、查询出条码所对应的流转余量
        double unQty = 0;
        double tempunQty = this.materialtransferMapper.selectUnQtyByIdCode(recMatEntity.getfPlanID(), recMatEntity.getfBarCode());

        //TODO CJM ?????? 2018-11-05 liujiajie 管控增加0.1
        unQty = tempunQty + 0.1;
        if (recMatEntity.getfWeight() > unQty) {
            throw new PDAException("此次流转会超过该批次可流转量");
        }
        // 3判断流转物料的类型，笔头，油墨还是硅油
        List<String> fproductypeTemp = this.materialtransferMapper.selectRecMatByplanIdCode(recMatEntity.getfPlanID(), ent.getfMatCode());
        if (StringUtil.isEmpty(fproductypeTemp) || fproductypeTemp.size() > 1) {
            throw new PDAException("当前流转物料类型为空或者查询到多条数据，请确认数据是否正确！" + "排程ID：" +
                    recMatEntity.getfPlanID() + "" + ent.getfMatCode() + fproductypeTemp);
        }

        ent.setfType(fproductypeTemp.get(0));
        YLQty = this.materialtransferMapper.selectYLQtyByplanIdType(recMatEntity.getfPlanID(), ent.getfType());
        if (YLQty <= 0) {
            throw new PDAException("流转余量小于0，不能流转!");
        } else if (YLQty < recMatEntity.getfWeight()) {
            throw new PDAException("流转余量小于此次流转量，不能流转!");
        }
        List<Double> xhlQty;
        double originalQty = 0; // 原发料数量
        double adjustQty = 0;//调整数量
        double difQty = 0; //差异数量
        // 4 判断总发料量和此次退料量是否会造成ERP中余量小于0.009(只判断类型为油墨和硅油的即可)
        if ((ent.getfType()).equals("油墨") || (ent.getfType()).equals("硅油")) {
            originalQty = recMatEntity.getfWeight();// 原流转数量
            xhlQty = this.getErpMargin(recMatEntity, "循环料流转");
            if (xhlQty != null && !xhlQty.isEmpty()) {
                difQty = xhlQty.get(0);
                adjustQty = xhlQty.get(1);
            } else {
                originalQty = recMatEntity.getfWeight();
            }
        } else {
            originalQty = recMatEntity.getfWeight();
        }
        // 5判断是否有实发量不等于应发量的数据
        countNeedUpdate = this.materialtransferMapper.selectCountActual(recMatEntity.getfInPlanID(), ent.getfMatCode());//recMatEntity.fInPlanID, ent.fMatCode
        // 7取出所对应的仓库和库位
        HashMap warelocaTemp = this.materialtransferMapper.selectWareLocation(ent.getfRecID());  //ent.fRecID
        if (StringUtil.isEmpty(warelocaTemp)) {
            throw new PDAException("根据领退料ID：" + ent.getfRecID() + ",未查询到仓库和库位!");
        }
        ent.setfWareCode(String.valueOf(warelocaTemp.get("TC_IMAM08")));
        ent.setfSeatCode(String.valueOf(warelocaTemp.get("TC_IMAM09")));
        // 8 判断转入和转出工单是否为结案工单
        if (!this.getOrderStatus(recMatEntity.getfOrderNo())) {
            throw new PDAException("转出工单已结案，不能进行流转!");
        }
        if (!getOrderStatus(recMatEntity.getfInOrderNo())) {
            throw new PDAException("转入工单已结案，不能进行流转!");
        }
        // 9 判断转出工单此料是否存在超领，有超领的不能转出
        count = this.materialtransferMapper.countsfaSupercollar(recMatEntity.getfOrderNo(), ent.getfMatCode());
        if (count > 0) {
            throw new PDAException("该工单下此料存在超领，不允许物料流转，请先超退");
        }

        // 1 插出拨出领退料表退料申请
        String OutRecMatID = UUID.randomUUID().toString();
        int updateNum = this.materialtransferMapper.insertOutRecmatbyfid(OutRecMatID, packMessage.getUser().getsCode(),
                originalQty, recMatEntity.getfWareCode(), recMatEntity.getfSeatCode(), ent.getfRecID());
        if (updateNum <= 0) {
            throw new PDAException("写入拨出领退料表退料申请失败!");
        }
        // 2 插出拨出领退料明细表退料明细
        String MG_RECMATDETAILFID2 = UUID.randomUUID().toString();
        updateNum = this.materialtransferMapper.insertOutDetail(MG_RECMATDETAILFID2,
                packMessage.getUser().getsCode(), originalQty, recMatEntity.getfWareCode(), recMatEntity.getfSeatCode(), OutRecMatID,
                recMatEntity.getfBarCode(), detailID);
        if (updateNum <= 0) {
            throw new PDAException("写入拨出领退料明细表退料明细失败!");
        }
        // 3 插入中间表退料
        double originaloradjustQty;
        if (adjustQty != 0) {
            originaloradjustQty = adjustQty;

        } else {
            originaloradjustQty = originalQty;
        }
        updateNum = this.materialtransferMapper.insertOutX5byfRecID(recMatEntity.getfWareCode(), recMatEntity.getfSeatCode(),
                originaloradjustQty, packMessage.getUser().getsCode(), recMatEntity.getfBarCode(),
                MG_RECMATDETAILFID2, ent.getfRecID());
        if (updateNum <= 0) {
            throw new PDAException("写入中间表拨出失败!");
        }
        //记录循环料流转拨出到批次库存表
        String bCUUID = UUID.randomUUID().toString();
        int countinsertmgbatchmatrecord = this.materialtransferMapper.insertmgbatchmatrecord(bCUUID, OutRecMatID, recMatEntity.getfBarCode(), originalQty,
                "循环料流转退料-拨出", packMessage.getUser().getsCode(), ent.getfType(), ent.getfRecID());
        if (countinsertmgbatchmatrecord <= 0) {
            throw new PDAException("插入拨出批次库存记录的数据失败!");
        }
        // 4 插入拨入领退料表退料申请
        String recMatID = UUID.randomUUID().toString();
        if (adjustQty != 0) {
            originaloradjustQty = adjustQty;
        } else {
            originaloradjustQty = originalQty;
        }
        updateNum = this.materialtransferMapper.insertInRecmatByfid(recMatID, recMatEntity.getfInPlanID(),
                recMatEntity.getfInMachineCode(), recMatEntity.getfInOrderNo(), packMessage.getUser().getsCode(),
                originaloradjustQty, recMatEntity.getfWareCode(), recMatEntity.getfSeatCode(), InProcss, ent.getfRecID());
        if (updateNum <= 0) {
            throw new PDAException("写入退料表失败!");
        }
        // 5 插入拨出领退料明细表退料明细
        String MG_RECMATDETAILfid5 = UUID.randomUUID().toString();
        if (adjustQty != 0) {
            originaloradjustQty = adjustQty;
        } else {
            originaloradjustQty = originalQty;
        }
        updateNum = this.materialtransferMapper.insertInRecmatDetailbydetailid(MG_RECMATDETAILfid5,
                recMatEntity.getfInPlanID(), recMatEntity.getfInMachineCode(), recMatEntity.getfInOrderNo(),
                packMessage.getUser().getsCode(), originaloradjustQty, recMatEntity.getfWareCode(), recMatEntity.getfSeatCode(), InProcss,
                recMatID, recMatEntity.getfBarCode(), detailID);
        if (updateNum <= 0) {
            throw new PDAException("写入退料详细表失败!");
        }
        // 6 插入中间表退料
        if (adjustQty != 0) {
            originaloradjustQty = adjustQty;
        } else {
            originaloradjustQty = originalQty;
        }
        updateNum = this.materialtransferMapper.insertInX5SQLbyrecid(recMatEntity.getfInOrderNo(), recMatEntity.getfWareCode(),
                recMatEntity.getfSeatCode(), originaloradjustQty, packMessage.getUser().getsCode(),
                recMatEntity.getfBarCode(), recMatEntity.getfInMachineCode(), InProcss, MG_RECMATDETAILfid5,
                ent.getfRecID());
        if (updateNum <= 0) {
            throw new PDAException("写入中间表失败!");
        }
        String bRUUID = UUID.randomUUID().toString();
        //记录循环料流转拨入到批次库存表
        if (adjustQty != 0) {
            originaloradjustQty = adjustQty;
        } else {
            originaloradjustQty = originalQty;
        }
        int bmCount = this.materialtransferMapper.insertBatchMatByrecid(bRUUID, recMatID, recMatEntity.getfBarCode(), originaloradjustQty,
                "循环料流转领料-拨入", packMessage.getUser().getsCode(), ent.getfType(), recMatEntity.getfInMachineCode(),
                recMatEntity.getfInOrderNo(), recMatEntity.getfWareCode(),
                recMatEntity.getfSeatCode(), InProcss, ent.getfRecID());
        if (bmCount <= 0) {
            throw new PDAException("插入拨入批次库存记录的数据失败!");
        }
        // 处理未发满物料
        // 7 更新实发量不等于应发量的数据
        updateNum = this.materialtransferMapper.updateMatByparam(recMatEntity.getfInPlanID(), recMatEntity.getfPlanID(), ent.getfMatCode());
        if (updateNum <= 0 && countNeedUpdate > 0) {
            throw new PDAException("更新领料表失败");
        }
        // 8 如果流转的量小于调拨量，增加一个申请记录（申请量=未发满量countNeedUpdate-流转量
        if (countNeedUpdate > recMatEntity.getfWeight()) {
            updateNum = this.materialtransferMapper.insertinsertRecmatbyfrecid(UUID.randomUUID().toString(), recMatEntity.getfInPlanID(),
                    recMatEntity.getfInMachineCode(), recMatEntity.getfInOrderNo(), packMessage.getUser().getsCode(),
                    countNeedUpdate - recMatEntity.getfWeight(), ent.getfWareCode(), ent.getfSeatCode(), InProcss, ent.getfRecID());
            if (updateNum <= 0) {
                throw new PDAException("写入退料表失败!");
            }
        }
        // 更新mg_recmatdetail表,使mg_recmatdetail里的实发量与mg_recmat保持一致
        // 1 插出拨出领退料表退料申请
        updateNum = this.materialtransferMapper.updateOutRecmatdetailbyparam(recMatEntity.getfInPlanID(),
                recMatEntity.getfPlanID(), ent.getfMatCode());
        if (updateNum <= 0) {
            throw new PDAException("更新领退料详细表失败");
        }
        // throw new PDAException("回退数据");
    }

    @Override
    @DataBase(DataSourceNames.DSX5)
    @Transactional()
    public List<Double> getErpMargin(RecMatEntity recMatEntity, String type) {
        List<Double> list = new ArrayList<Double>();
        // 成品笔头发料向上取整
        BigDecimal QPA = new BigDecimal(0);
        BigDecimal sumyQty = new BigDecimal(0); // MES工单应发数
        double difQty = 0; // 差异量
        BigDecimal erpyQty = new BigDecimal(0);// erp应发量
        BigDecimal sumFrspqty = new BigDecimal(0);// mes工单已发
        double qty = 0; // 本次发料数量
        String fProcss = "";    //作业编码
        String fUnit = "";    //单位类型

        //作业类型
        // String cpSql = "select distinct FPROCSS FPROCSS ,FUNIT FUNIT from dsx5.mg_recmat where forderno = ? and fmatcode = ?";
        // List<HashMap> cplistTemp =  this.materialtransferMapper.selectProcessByNoCode(recMatEntity.fOrderNo,recMatEntity.fMatCode);
        List<HashMap> cplistTemp = this.materialtransferMapper.selectProcessByNoCode(recMatEntity.getfOrderNo(), recMatEntity.getfMatCode());
        if (StringUtil.isEmpty(cplistTemp) || cplistTemp.size() > 1) {
            throw new PDAException("工单:" + recMatEntity.getfOrderNo() + " 料号:" + recMatEntity.getfMatCode() + "获取作业类型为空或者查询到多条数据!" + cplistTemp);
        }

        fProcss = cplistTemp.get(0).get("FPROCSS") == null ? "" : String.valueOf(cplistTemp.get(0).get("FPROCSS"));
        fUnit = cplistTemp.get(0).get("FUNIT") == null ? "" : String.valueOf(cplistTemp.get(0).get("FUNIT"));

        // QPA
        //cpSql = "select sfa05,sfa161 from ds2.sfa_file where sfa01 = ? and sfa03 = ? and sfa08= ? and sfa12 = ?";
        //recMatEntity.fOrderNo, recMatEntity.fMatCode,fProcss,fUnit
        List<HashMap> QPAlistTemp = this.materialtransferMapper.selectSfaQPAByNoCode(recMatEntity.getfOrderNo(), recMatEntity.getfMatCode(), fProcss, fUnit);

        if (StringUtil.isEmpty(QPAlistTemp) || QPAlistTemp.size() > 1) {
            //throw new PDAException("工单:"+recMatEntity.fOrderNo+" 料号:"+recMatEntity.fMatCode+"获取QPA为空或者查询到多条数据!"+QPAlistTemp);
            throw new PDAException("工单:" + recMatEntity.getfOrderNo() + " 料号:" + recMatEntity.getfMatCode() + "获取QPA为空或者查询到多条数据!" + QPAlistTemp);
        }

        erpyQty = new BigDecimal(QPAlistTemp.get(0).get("SFA05").toString());
        QPA = new BigDecimal(QPAlistTemp.get(0).get("SFA161").toString());

        // 工单应发数
        if ("笔头".equals(recMatEntity.getfType())) {
            //cpSql = " select nvl(sum(CEIL(ROUND(FPLANQTY * " + QPA + ",3))),0) as sumQty from dsx5.mg_orderplan where forderno = ? and fclassjob  in ( 'F','R') and fsendorder = 1 and fisfinishproduced = 'Y'";
            sumyQty = this.materialtransferMapper.selectsumQtyByordernopen(recMatEntity.getfOrderNo(), QPA);//recMatEntity.fOrderNo
        } else if ("油墨".equals(recMatEntity.getfType()) || "硅油".equals(recMatEntity.getfType())) {
            //  cpSql = "select nvl(sum(ROUND(FPLANQTY * " + QPA + ", 3)),0) as sumQty from dsx5.mg_orderplan where forderno = ? and fclassjob  in ( 'F','R') and fsendorder = 1 and fisfinishproduced = 'Y'";
            sumyQty = this.materialtransferMapper.selectsumQtyByordernoink(recMatEntity.getfOrderNo(), QPA);//recMatEntity.fOrderNo
        }

        // mes工单总已发量
        //  cpSql = "select NVL(SUM(CASE WHEN FOPTYPE = '领料' THEN FRSPQTY  WHEN FOPTYPE = '退料' THEN FRSPQTY * -1 END), 0) AS OVEROUTMAT from dsx5.mg_recmatdetail where forderno = ? and fmatcode = ?";
        sumFrspqty = this.materialtransferMapper.selectsumMESQtyByorderno(recMatEntity.getfOrderNo(), recMatEntity.getfMatCode());// recMatEntity.fOrderNo, recMatEntity.fMatCode

        //   BigDecimal fWeight = new BigDecimal(String.valueOf(recMatEntity.fWeight));
        BigDecimal fWeight = new BigDecimal(String.valueOf(recMatEntity.getfWeight()));
        difQty = sumyQty.subtract(erpyQty).doubleValue();
        if ("批次发料".equals(type) && difQty != 0) {
            int zQty = (int) difQty;
            if (sumFrspqty.intValue() + fWeight.intValue() == erpyQty.intValue() && difQty <= 30) {
                //只改MES领发料
                qty = fWeight.intValue() + zQty;

            } else if (sumFrspqty.intValue() + fWeight.intValue() == sumyQty.intValue() && Math.abs(difQty) <= 30) {
                //只改ERP改中间表
                qty = fWeight.intValue() - zQty;
            }
        } else if ("批次退料".equals(type) && difQty != 0) {
            if (sumFrspqty.subtract(fWeight.add(sumyQty.subtract(erpyQty))).floatValue() == erpyQty.floatValue() && Math.abs(difQty) <= 0.1) {
                qty = fWeight.floatValue() + difQty;
            }
        } else if ("循环料流转".equals(type) && difQty != 0) {
            if (sumFrspqty.subtract(fWeight.add(sumyQty.subtract(erpyQty))).floatValue() == erpyQty.floatValue() && Math.abs(difQty) <= 0.1) {
                qty = fWeight.floatValue() + difQty;
            }
        }
        list.add(difQty);
        list.add(qty);


        return list;
    }

    @Override
    @DataBase(DataSourceNames.DSX5)
    @Transactional()
    public boolean getOrderStatus(String fOrderNo) {
// 获取ERP中该工单状态
        String sql = "SELECT SFB04 FROM DS2.SFB_FILE WHERE SFB01=? ";

        // 状态码为8的是结案工单，不可以进行流转
        if ("8".equals(this.materialtransferMapper.getOrderStatus(fOrderNo))) {
            return false;
        } else {
            return true;
        }
    }


    @Override
    @DataBase(DataSourceNames.DSX5)
    @Transactional()
    public RecMatEntity functionGetQty(PackMessage packMessage) {
        RecMatEntity recMatEntity = JSON.parseObject(packMessage.getMessage(), RecMatEntity.class);
        RecMatEntity entity = new RecMatEntity();
        entity.setfBarCode("");
        // 0、计算余量
        entity.setfWeight(this.materialtransferMapper.selectallowanceLDIFFRESULTByParm(recMatEntity.getfPlanID(), recMatEntity.getfType()));
        // 1,取出最后使用的条码
        if (entity.getfWeight() < 0) {
            entity.setfWeight(0.0);
        }
        String barcodeTemp = this.materialtransferMapper.selectallastfbatchByParm(recMatEntity.getfPlanID(), recMatEntity.getfType());
        if (StringUtil.isEmpty(barcodeTemp)) {
            throw new PDAException("没有符合条件的批次条码信息");
        }
        entity.setfBarCode(barcodeTemp);
        return entity;
    }

}
